package com.tyfspring.beans.factory;

import com.tyfspring.beans.FactoryBean;
import com.tyfspring.beans.config.BeanDefinition;
import com.tyfspring.beans.config.BeanPostProcessor;
import com.tyfspring.beans.exception.BeansException;
import com.tyfspring.beans.support.FactoryBeanRegistrySupport;
import com.tyfspring.core.convert.ConversionService;
import com.tyfspring.util.StringValueResolver;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description Spring容器的基础实现
 * @Author shallow
 * @Date 2023/3/27 15:31
 */

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory{

    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
    //用于存储FactoryBean类型的对象的实例
    private final Map<String, Object> factoryBeanObjectCache = new HashMap<>();

    private final List<StringValueResolver> embeddedValueResolvers = new ArrayList<>();

    private ConversionService conversionService;

    @Override
    public Object getBean(String name) throws BeansException {
//        Object sharedInstance = getSingleton(name);
//        if (sharedInstance!=null) {
//            return getObjectForBeanInstance(sharedInstance,name);
//        }
//        BeanDefinition beanDefinition = getBeanDefinition(name);
//        Object bean = createBean(name, beanDefinition,null);
//        return getObjectForBeanInstance(bean,name);
        return doGetBean(name, null);
    }

    /**
     * 根据bean实例，创建该bean实例的包装类对象
     * @param beanInstance
     * @param beanName
     * @return
     */
//    protected Object getObjectForBeanInstance(Object beanInstance, String beanName){
//        Object object = beanInstance;
//        if (beanInstance instanceof FactoryBean) {
////         如果是FactoryBean，从FactoryBean的getObject中创建bean
//            FactoryBean factoryBean = (FactoryBean) beanInstance;
//            try {
//                if (factoryBean.isSingleton()) {
//                    //如果是单例bean的FactoryBean对象，从缓存中获取
//                    object = this.factoryBeanObjectCache.get(beanName);
//                    if (object==null) {
//                        object = factoryBean.getObject();
//                    }
//                }else{
//                    //原型bean，创建bean
//                    object = factoryBean.getObject();
//                }
//            } catch (Exception e) {
//                throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", e);
//            }
//        }
//        return object;
//    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return ((T)getBean(name));
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, args);
    }

    protected <T> T doGetBean(String name, Object[] args) {
        Object shareInstance = getSingleton(name);
        if (shareInstance !=null) {
            //如果是FactoryBean,则需要调用FactoryBean.getObject()
            return (T)getObjectForBeanInstance(shareInstance,name);
        }
        BeanDefinition beanDefinition = getBeanDefinition(name);
        Object bean = createBean(name, beanDefinition, args);
        return (T)getObjectForBeanInstance(bean,name);
    }

    /**
     * 根据bean实例，创建该bean实例的包装类对象
     * @param beanInstance
     * @param beanName
     * @return
     */
    private Object getObjectForBeanInstance(Object beanInstance, String beanName) {
        if (!(beanInstance instanceof FactoryBean)){
            return beanInstance;
        }
        Object object = getCachedObjectForFactoryBean(beanName);
        if (object == null){
            FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
            object = getObjectFromFactoryBean(factoryBean,beanName);
        }
        return object;
    }

    //获取BeanDefinition
    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    //创建bean
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException;

    //是否有BeanDefinition
    protected abstract boolean containsBeanDefinition(String beanName);
//    @Override
//    public boolean containsBean(String name) {
//        return containsBeanDefinition(name);
//    }



    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        //有则覆盖
        this.beanPostProcessors.remove(beanPostProcessor);
        this.beanPostProcessors.add(beanPostProcessor);
    }

    public List<BeanPostProcessor> getBeanPostProcessors() {
        return this.beanPostProcessors;
    }

    @Override
    public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
        this.embeddedValueResolvers.add(valueResolver);
    }

    @Override
    public String resolveEmbeddedValue(String value) {
        String result = value;
        for (StringValueResolver resolver : this.embeddedValueResolvers) {
            result = resolver.resolveStringValue(result);
        }
        return result;
    }

    @Override
    public void setConversionService(ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    @Override
    public ConversionService getConversionService() {
        return conversionService;
    }
}
